#ifndef __LINUX_IRQ_H__
#define __LINUX_IRQ_H__

#include "linux/slab.h"
#include "linux/types.h"
#include "linux/list.h"
#include "linux/of_irq.h"
#include "linux/irqdomain.h"
#include "linux/bug.h"
#include "linux/kernel.h"
#include "asm/ptrace.h"
#include "linux/irqhandler.h"


enum
{
    IRQCHIP_SET_TYPE_MASKED = (1 << 0),
    IRQCHIP_EOI_IF_HANDLED = (1 << 1),
    IRQCHIP_MASK_ON_SUSPEND = (1 << 2),
    IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
    IRQCHIP_SKIP_SET_WAKE = (1 << 4),
    IRQCHIP_ONESHOT_SAFE = (1 << 5),
    IRQCHIP_EOI_THREADED = (1 << 6),
};

enum
{
    IRQD_TRIGGER_MASK = 0xf,
    IRQD_SETAFFINITY_PENDING = (1 << 8),
    IRQD_NO_BALANCING = (1 << 10),
    IRQD_PER_CPU = (1 << 11),
    IRQD_AFFINITY_SET = (1 << 12),
    IRQD_LEVEL = (1 << 13),
    IRQD_WAKEUP_STATE = (1 << 14),
    IRQD_MOVE_PCNTXT = (1 << 15),
    IRQD_IRQ_DISABLED = (1 << 16),
    IRQD_IRQ_MASKED = (1 << 17),
    IRQD_IRQ_INPROGRESS = (1 << 18),
    IRQD_WAKEUP_ARMED = (1 << 19),
};

struct irq_data;
struct irq_desc;

struct irq_chip
{
     char *name;
    unsigned int (*irq_startup)(struct irq_data *data);
    void (*irq_shutdown)(struct irq_data *data);
    void (*irq_enable)(struct irq_data *data);
    void (*irq_disable)(struct irq_data *data);

    void (*irq_ack)(struct irq_data *data);
    void (*irq_mask)(struct irq_data *data);
    void (*irq_mask_ack)(struct irq_data *data);
    void (*irq_unmask)(struct irq_data *data);
    void (*irq_eoi)(struct irq_data *data);

    //int (*irq_set_affinity)(struct irq_data *data,  struct cpumask *dest, int force);
    int (*irq_retrigger)(struct irq_data *data);
    int (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
    int (*irq_set_wake)(struct irq_data *data, unsigned int on);

    void (*irq_bus_lock)(struct irq_data *data);
    void (*irq_bus_sync_unlock)(struct irq_data *data);

    void (*irq_cpu_online)(struct irq_data *data);
    void (*irq_cpu_offline)(struct irq_data *data);

    void (*irq_suspend)(struct irq_data *data);
    void (*irq_resume)(struct irq_data *data);
    void (*irq_pm_shutdown)(struct irq_data *data);

    void (*irq_calc_mask)(struct irq_data *data);

    //void (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
    int (*irq_request_resources)(struct irq_data *data);
    void (*irq_release_resources)(struct irq_data *data);

    //void (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
    //void (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);

    unsigned long flags;
};

struct irq_common_data 
{
    unsigned int  state_use_accessors;
#ifdef CONFIG_NUMA
	unsigned int		node;
#endif
	void			*handler_data;
	//cpumask_var_t		affinity;
};

struct irq_data
{
    uint32_t mask;
    unsigned int irq;
    unsigned long hwirq;
    unsigned int node;
    unsigned int state_use_accessors;
    struct irq_chip *chip;
    struct irq_domain *domain;
    struct irq_data *parent_data;
    struct irq_common_data	*common;
    void *handler_data;
    void *chip_data;
    //struct msi_desc *msi_desc;
};

enum
{
    IRQ_TYPE_NONE = 0x00000000,
    IRQ_TYPE_EDGE_RISING = 0x00000001,
    IRQ_TYPE_EDGE_FALLING = 0x00000002,
    IRQ_TYPE_EDGE_BOTH = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING),
    IRQ_TYPE_LEVEL_HIGH = 0x00000004,
    IRQ_TYPE_LEVEL_LOW = 0x00000008,
    IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH),
    IRQ_TYPE_SENSE_MASK = 0x0000000f,
    IRQ_TYPE_DEFAULT = IRQ_TYPE_SENSE_MASK,

    IRQ_TYPE_PROBE = 0x00000010,

    IRQ_LEVEL = (1 << 8),
    IRQ_PER_CPU = (1 << 9),
    IRQ_NOPROBE = (1 << 10),
    IRQ_NOREQUEST = (1 << 11),
    IRQ_NOAUTOEN = (1 << 12),
    IRQ_NO_BALANCING = (1 << 13),
    IRQ_MOVE_PCNTXT = (1 << 14),
    IRQ_NESTED_THREAD = (1 << 15),
    IRQ_NOTHREAD = (1 << 16),
    IRQ_PER_CPU_DEVID = (1 << 17),
    IRQ_IS_POLLED = (1 << 18),
};

#define ARCH_IRQ_INIT_FLAGS	(IRQ_NOREQUEST | IRQ_NOPROBE)
#define IRQ_DEFAULT_INIT_FLAGS	ARCH_IRQ_INIT_FLAGS


#define IRQF_MODIFY_MASK                                                  \
    (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST |                  \
     IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING |      \
     IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \
     IRQ_IS_POLLED)

#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)

#define ARCH_IRQ_INIT_FLAGS	(IRQ_NOREQUEST | IRQ_NOPROBE)
#define IRQ_DEFAULT_INIT_FLAGS	ARCH_IRQ_INIT_FLAGS

extern void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle);
extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
extern unsigned int irq_get_trigger_type(unsigned int irq);
extern struct irq_data *irq_get_irq_data(unsigned int irq);
extern int irq_set_irq_type(unsigned int irq, unsigned int type);
extern uint32_t irqd_get_trigger_type(struct irq_data *d);
extern unsigned int irq_get_trigger_type(unsigned int irq);
extern void *irq_get_chip_data(unsigned int irq);
extern void *irq_data_get_irq_chip_data(struct irq_data *d);
extern void *irq_get_handler_data(unsigned int irq);
extern void *irq_data_get_irq_handler_data(struct irq_data *d);
extern int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, void *owner);
extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, unsigned long flags);
extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
extern int irq_set_chip_data(unsigned int irq, void *data);
extern void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set);
extern void handle_level_irq(unsigned int irq, struct irq_desc *desc);;
extern void handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc);
extern void __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,char *name);
extern int irq_set_handler_data(unsigned int irq, void *data);
extern int irq_startup(struct irq_desc *desc, int resend);

#define irq_alloc_descs(irq, from, cnt, node)	__irq_alloc_descs(irq, from, cnt, node, NULL)
#define irq_alloc_descs_from(from, cnt, node)	irq_alloc_descs(-1, from, cnt, node)

extern int nr_irqs;

#define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX)

#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)

static inline int irqd_irq_disabled(struct irq_data *d)
{
	//return __irqd_to_state(d) & IRQD_IRQ_DISABLED;
    return 0;
}

#define __irq_enter()                      \
    do                                     \
    {                                      \
        preempt_count_add(HARDIRQ_OFFSET); \
    } while (0)

#endif

